<template>
    <el-dialog class="dialog" :title="title" :visible.sync="dialogVisible" @opened="open" @closed="cancel" width="80%">
        <el-form :inline="true" :model="queryParams" :rules="rule" ref="form">
            <el-form-item prop="deptId" label="请选择所属工厂">
                <treeselect v-model="queryParams.deptId" :options="deptOptions" placeholder="归属工厂"
                    style="width: 200px;line-height: 38px;" :show-count="true" @input="getDeviceList" />
            </el-form-item>
            <el-form-item label="请选择对比设备" prop="device">
                <el-select v-model="queryParams.device" value-key="id" placeholder="设备名称" style="width: 200px"
                    clearable>
                    <el-option v-for="item in deviceList" :key="item.id" :label="item.name" :value="item" />
                </el-select>
            </el-form-item>
            <el-form-item label="请选择对比指标" prop="fields">
                <el-select v-model="queryParams.fields" placeholder="指标名称" style="width: 400px;" clearable
                    :multiple="true" :multiple-limit="2">
                    <el-option v-for="variable in variableList" :key="variable.key" :label="variable.name"
                        :value="variable.key" />
                </el-select>
            </el-form-item>
            <el-form-item label="请选择时间段" prop="timeRange">
                <el-date-picker v-model="queryParams.timeRange" type="datetimerange" start-placeholder="开始时间"
                    end-placeholder="结束时间" :picker-options="pickerOptions" align="center"
                    :default-time="['08:00:00']"></el-date-picker>
            </el-form-item>
            <el-button @click="confirm">确定</el-button>
        </el-form>
        <div v-loading="loading" element-loading-text="加载中" element-loading-spinner="el-icon-loading" id="compareChart"
            ref="compareChart" style="height: 540px;"></div>
        <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="cancel">关 闭</el-button>
        </span>
    </el-dialog>
</template>
<script>
import { listVariable } from "@/api/oil/variable";
import { listDevice } from "@/api/oil/device";
import { getCompareData } from "../../../api/oil/device_data";
import Treeselect from "@riophae/vue-treeselect";
import { deptTreeSelect } from "@/api/system/user";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import * as echarts from 'echarts'
import DateTool from "../../../utils/DateTool";
export default {
    components: { Treeselect },
    props: {
        device: {
            default: null
        },
        dialogVisible: {
            default: false
        }
    },
    data() {
        return {
            title: "跨设备数据对比",
            variableList: [],
            checkedList: [],
            deptOptions: [],
            queryParams: {},
            deviceList: [],
            pickerOptions: null,
            startDate: null,
            myChart: null,
            rule: {
                device: [
                    { required: true, message: "请选择对比设备", trigger: "blur" }
                ],
                fields: [
                    { required: true, message: "请选择对比指标", trigger: "blur" }
                ],
                timeRange: [
                    { required: true, message: "请选择对比时间", trigger: "blur" }
                ]
            },
            dataA: [], //传入设备的数据
            dataB: [], //选择设备的数据
            times: [],  //x轴所有时间戳
            loading: false,
            samplingAction: false // 是否已完成非降采样展示切换
        }
    },
    created() {
        this.getDeptTree();
        this.getVariables();
        this.initPickerOption();
        window.addEventListener('resize', this.handleResize);
    },
    // 监听 dataZoom 事件，动态调整降采样
    mounted() {
        if (this.myChart) {
            this.myChart.on('dataZoom', this.handleDataZoom);
        }
    },
    destroyed() {
        if (this.myChart) {
            this.myChart.off('dataZoom', this.handleDataZoom);
        }
    },
    beforeDestroy() {
        window.removeEventListener('resize', this.handleResize);
        if (this.myChart) {
            this.myChart.dispose();//清理图表实例
        }
    },
    methods: {
        handleResize() {
            if (this.myChart) {
                this.myChart.resize();
            }
        },
        //控制自定义查询时间时最长查询三个月
        initPickerOption() {
            this.pickerOptions = {
                // onPick：选中日期时的回调函数，在这里对选中的日期进行处理{maxDate：后选中日期；minDate：第一个选中的日期}
                onPick: ({ maxDate, minDate }) => {
                    this.startDate = minDate && minDate.getTime()
                    if (maxDate) {
                        // 选中后一个时，要把第一个的赋值清空
                        this.startDate = ''
                    }
                },
                disabledDate: (time) => {
                    // 选中第一个后，后一个前后3个月可选，超出的不可选，超出当前天也不可选，这里的月份按需求设定
                    const minTime = new Date(this.startDate).setMonth(new Date(this.startDate).getMonth() - 3)
                    const maxTime = new Date(this.startDate).setMonth(new Date(this.startDate).getMonth() + 3)
                    return time.getTime() > Date.now() || (this.startDate ? (time.getTime() < minTime || time.getTime() > maxTime) : false)
                }
            }
        },
        /** 查询部门下拉树结构 */
        getDeptTree() {
            deptTreeSelect().then(response => {
                this.deptOptions = response.data;
            });
        },
        /** 查询设备管理列表 */
        getDeviceList() {
            listDevice(this.queryParams).then(response => {
                // this.queryParams.device=null;
                this.deviceList = response.rows;
            });
        },
        getVariables() {
            listVariable({ pageSize: 5000 }).then(response => {
                this.variableList = response.rows;
            })
        },
        confirm() {
            this.$refs["form"].validate(valid => {
                if (valid) {
                    var deviceCode = this.device.code + "," + this.queryParams.device.code;
                    var startTime = DateTool.dateToStr(this.queryParams.timeRange[0]);
                    var endTime = DateTool.dateToStr(this.queryParams.timeRange[1]);
                    var queryData = { deviceCode: deviceCode, fields: this.queryParams.fields, startTime: startTime, endTime: endTime };
                    this.loading = true;
                    getCompareData(queryData).then(response => {
                        this.loading = false;
                        this.dataA = response.data[this.device.code];
                        this.dataB = response.data[this.queryParams.device.code];
                        var times = this.dataA.map(item => item.timeStamp);
                        this.times = times.concat(this.dataB.map(item => item.timeStamp));
                        console.log(this.times)
                        this.init();
                    })
                }
            })
        },
        /**
         * 优化大数据量渲染，减少前端等待时间
         * 1. 降采样：对allTimes进行采样，减少点数
         * 2. 当显示区域缩小到1天时，取消降采样
         * 3. echarts开启性能优化
         * 4. 滚轮缩放到1天内显示全部点，超过2000点时重新降采样
         * 5. 使用samplingAction变量记录是否进行了非降采样展示切换
         */
        handleDataZoom(params) {
            if (!this.myChart) return;
            const option = this.myChart.getOption();
            const xAxis = option.xAxis && option.xAxis[0];
            const dataZoom = option.dataZoom && option.dataZoom[0];
            if (!xAxis || !xAxis.data || !dataZoom) return;
            const allTimes = xAxis.data;
            let startIdx = 0, endIdx = allTimes.length - 1;
            if (typeof dataZoom.startValue === 'number' && typeof dataZoom.endValue === 'number') {
                startIdx = dataZoom.startValue;
                endIdx = dataZoom.endValue;
            } else if (params.batch && params.batch.length > 0) {
                startIdx = params.batch[0].startValue || 0;
                endIdx = params.batch[0].endValue || (allTimes.length - 1);
            } else if (params.startValue !== undefined) {
                startIdx = params.startValue;
                endIdx = params.endValue;
            }
            const startTime = allTimes[startIdx];
            const endTime = allTimes[endIdx];
            if (startTime && endTime) {
                const start = new Date(startTime).getTime();
                const end = new Date(endTime).getTime();

                //console.log(start, end);
                // 非降采样切换逻辑
                if (!this.samplingAction && end - start <= 24 * 60 * 60 * 1000) {
                    // 进入非降采样模式，记录当前区域
                    this.samplingAction = {
                        startTime,
                        endTime
                    };
                    this.initChartWithoutSampling(startTime, endTime);
                } else if (this.samplingAction) {
                    // 已经是非降采样模式
                    // 判断当前区域是否还在记录的非降采样区域内
                    console.log("当前区域：", startTime, endTime);
                    console.log("记录区域：", this.samplingAction.startTime, this.samplingAction.endTime);
                    const recordStart = new Date(this.samplingAction.startTime).getTime();
                    const recordEnd = new Date(this.samplingAction.endTime).getTime();
                    // 如果当前区域大于等于记录的区域（即放大），不再切换
                    if (start > recordStart && end < recordEnd) {
                        // 不做切换
                        return;
                    }
                    // 如果当前区域小于记录的区域（即缩小），恢复降采样
                    if (start <= recordStart || end >= recordEnd) {
                        this.samplingAction = false;
                        this.init();
                        this.$nextTick(() => {
                            if (this.myChart) {
                                this.myChart.dispatchAction({
                                    type: 'dataZoom',
                                    startValue: startIdx,
                                    endValue: endIdx
                                });
                            }
                        });
                    }
                }
            }
        },
        /**
         * initChartWithoutSampling 只渲染可视区域时间范围内的全部点
         * @param {String} [startTime] - 可视区域起始时间戳（字符串）
         * @param {String} [endTime] - 可视区域结束时间戳（字符串）
         */

        initChartWithoutSampling(startTime, endTime) {
            if (this.myChart) {
                this.myChart.clear();
            } else {
                this.myChart = echarts.init(document.getElementById("compareChart"));
            }
            this.bindChartEvents();

            // 生成对齐的时间点（每隔5分钟的整点）
            let allTimesSet = new Set();
            this.dataA.forEach(item => allTimesSet.add(item.timeStamp));
            this.dataB.forEach(item => allTimesSet.add(item.timeStamp));
            let allTimesRaw = Array.from(allTimesSet).sort();

            // 获取时间范围
            let minTime = allTimesRaw.length ? new Date(allTimesRaw[0]).getTime() : null;
            let maxTime = allTimesRaw.length ? new Date(allTimesRaw[allTimesRaw.length - 1]).getTime() : null;
            if (startTime && endTime) {
                minTime = new Date(startTime).getTime();
                maxTime = new Date(endTime).getTime();
            }

            // 生成每隔5分钟的时间点
            const alignedTimes = [];
            if (minTime !== null && maxTime !== null) {
                let t = minTime - (minTime % (5 * 60 * 1000)); // 向下取整到5分钟
                while (t <= maxTime) {
                    const date = new Date(t);
                    const yyyy = date.getFullYear();
                    const MM = String(date.getMonth() + 1).padStart(2, '0');
                    const dd = String(date.getDate()).padStart(2, '0');
                    const hh = String(date.getHours()).padStart(2, '0');
                    const mm = String(date.getMinutes()).padStart(2, '0');
                    const ss = String(date.getSeconds()).padStart(2, '0');
                    alignedTimes.push(`${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`);
                    t += 5 * 60 * 1000;
                }
            }

            console.log("对齐后的时间点：", alignedTimes);

            // 将原始数据的时间戳对齐到5分钟整点作为key
            function alignTo5Min(ts) {
                const date = new Date(ts);
                date.setSeconds(0, 0);
                const minutes = date.getMinutes();
                date.setMinutes(minutes - (minutes % 5));
                const yyyy = date.getFullYear();
                const MM = String(date.getMonth() + 1).padStart(2, '0');
                const dd = String(date.getDate()).padStart(2, '0');
                const hh = String(date.getHours()).padStart(2, '0');
                const mm = String(date.getMinutes()).padStart(2, '0');
                const ss = String(date.getSeconds()).padStart(2, '0');
                return `${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`;
            }

            const dataAMap = new Map(this.dataA.map(item => [alignTo5Min(item.timeStamp), item]));
            const dataBMap = new Map(this.dataB.map(item => [alignTo5Min(item.timeStamp), item]));

            console.log("dataAMap:", dataAMap);
            console.log("dataBMap:", dataBMap);

            const variables = this.queryParams.fields;
            const variableMap = new Map(this.variableList.map(item => [item.key, item.name]));

            const series = [];
            const gridIndex = [];
            const xAxis = [];
            const yAxis = [];
            const grid = [];
            const legend = [];

            variables.forEach((element, index) => {
                gridIndex.push(index);
                const top = 270 * index;
                grid.push({ top: top + 25 + "px", left: "2%", right: "1%", height: (400 / variables.length) + "px" });
                xAxis.push({
                    type: 'category',
                    gridIndex: index,
                    data: alignedTimes,
                    axisLabel: {
                        formatter(value) {
                            const [date, time] = value.split(" ");
                            return (time || "") + "\n" + (date ? date.substring(5) : "");
                        },
                        show: true,
                        textStyle: { color: "#fff" }
                    }
                });
                yAxis.push({ type: 'value', gridIndex: index, axisLabel: { textStyle: { color: "#fff" } } });

                // 对齐数据到5分钟整点
                
                const dataAForVar = alignedTimes.map(time => {
                    const item = dataAMap.get(time);
                    return [time, item ? item[element] : null];
                });
                const dataBForVar = alignedTimes.map(time => {
                    const item = dataBMap.get(time);
                    return [time, item ? item[element] : null];
                });

                console.log("dataAForVar:", dataAForVar);
                console.log("dataBForVar:", dataBForVar);

                const objA = {
                    name: this.device.name + variableMap.get(element),
                    type: 'line',
                    xAxisIndex: index,
                    yAxisIndex: index,
                    data: dataAForVar,
                    sampling: false,
                    large: true,
                    largeThreshold: 2000
                };
                const objB = {
                    name: this.queryParams.device.name + variableMap.get(element),
                    type: 'line',
                    xAxisIndex: index,
                    yAxisIndex: index,
                    data: dataBForVar,
                    sampling: false,
                    large: true,
                    largeThreshold: 2000
                };
                series.push(objA, objB);
                legend.push({
                    data: [objA.name, objB.name],
                    textStyle: { color: "#fff" },
                    top: top
                });
            });

            if (variables.length === 1) {
                grid[0].top = "15%";
                grid[0].bottom = "10%";
                grid[0].height = "auto";
                legend[0].top = "10%";
            }

            const option = {
                tooltip: { trigger: 'axis' },
                legend,
                grid,
                xAxis,
                yAxis,
                series,
                dataZoom: [
                    { type: 'inside', start: 0, end: 100, xAxisIndex: gridIndex },
                    { type: 'slider', start: 0, end: 100, xAxisIndex: gridIndex }
                ]
            };
            this.myChart.setOption(option);
        },
        // 在init和initChartWithoutSampling中绑定dataZoom事件
        bindChartEvents() {
            if (this.myChart) {
                this.myChart.off('dataZoom', this.handleDataZoom); // 避免重复绑定
                this.myChart.on('dataZoom', this.handleDataZoom);
            }
        },
        init() {
            if (this.myChart) {
                this.myChart.clear();
            } else {
                this.myChart = echarts.init(document.getElementById("compareChart"));
            }

            this.bindChartEvents();


            // 提取所有唯一的时间戳并排序
            const allTimesSet = new Set(this.dataA.map(item => item.timeStamp));
            this.dataB.forEach(item => allTimesSet.add(item.timeStamp));
            let allTimes = Array.from(allTimesSet).sort();

            // 获取时间范围
            let minTime = allTimes.length ? new Date(allTimes[0]).getTime() : null;
            let maxTime = allTimes.length ? new Date(allTimes[allTimes.length - 1]).getTime() : null;

            // 生成每隔5分钟的时间点
            const alignedTimes = [];
            if (minTime !== null && maxTime !== null) {
                let t = minTime - (minTime % (5 * 60 * 1000)); // 向下取整到5分钟
                while (t <= maxTime) {
                    const date = new Date(t);
                    const yyyy = date.getFullYear();
                    const MM = String(date.getMonth() + 1).padStart(2, '0');
                    const dd = String(date.getDate()).padStart(2, '0');
                    const hh = String(date.getHours()).padStart(2, '0');
                    const mm = String(date.getMinutes()).padStart(2, '0');
                    const ss = String(date.getSeconds()).padStart(2, '0');
                    alignedTimes.push(`${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`);
                    t += 5 * 60 * 1000;
                }
            }
            allTimes = alignedTimes; // 使用对齐后的时间点
            console.log("对齐后的时间点：", alignedTimes);


            // 降采样：只取部分点（如每隔N个点取1个），N可根据allTimes长度动态调整
            const MAX_POINTS = 2000;
            if (allTimes.length > MAX_POINTS) {
                const step = Math.ceil(allTimes.length / MAX_POINTS);
                allTimes = allTimes.filter((_, idx) => idx % step === 0);
            }

            // 构建时间戳到数据的Map，提升查找效率
            // 将原始数据的时间戳对齐到5分钟整点作为key
            function alignTo5Min(ts) {
                const date = new Date(ts);
                date.setSeconds(0, 0);
                const minutes = date.getMinutes();
                date.setMinutes(minutes - (minutes % 5));
                const yyyy = date.getFullYear();
                const MM = String(date.getMonth() + 1).padStart(2, '0');
                const dd = String(date.getDate()).padStart(2, '0');
                const hh = String(date.getHours()).padStart(2, '0');
                const mm = String(date.getMinutes()).padStart(2, '0');
                const ss = String(date.getSeconds()).padStart(2, '0');
                return `${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`;
            }

            const dataAMap = new Map(this.dataA.map(item => [alignTo5Min(item.timeStamp), item]));
            const dataBMap = new Map(this.dataB.map(item => [alignTo5Min(item.timeStamp), item]));

            const variables = this.queryParams.fields;
            const variableMap = new Map(this.variableList.map(item => [item.key, item.name]));

            const series = [];
            const gridIndex = [];
            const xAxis = [];
            const yAxis = [];
            const grid = [];
            const legend = [];

            variables.forEach((element, index) => {
                gridIndex.push(index);
                const top = 270 * index;
                grid.push({ top: top + 25 + "px", left: "2%", right: "1%", height: (400 / variables.length) + "px" });
                xAxis.push({
                    type: 'category',
                    gridIndex: index,
                    data: allTimes,
                    axisLabel: {
                        formatter(value) {
                            const [date, time] = value.split(" ");
                            return (time || "") + "\n" + (date ? date.substring(5) : "");
                        },
                        show: true,
                        textStyle: { color: "#fff" }
                    }
                });
                yAxis.push({ type: 'value', gridIndex: index, axisLabel: { textStyle: { color: "#fff" } } });

                // 预先批量生成数据，避免多次find
                const dataAForVar = allTimes.map(time => {
                    const item = dataAMap.get(time);
                    return [time, item ? item[element] : null];
                });
                const dataBForVar = allTimes.map(time => {
                    const item = dataBMap.get(time);
                    return [time, item ? item[element] : null];
                });

                const objA = {
                    name: this.device.name + variableMap.get(element),
                    type: 'line',
                    xAxisIndex: index,
                    yAxisIndex: index,
                    data: dataAForVar,
                    sampling: 'lttb', // ECharts 5+ 支持的降采样算法
                    large: true,      // 开启大数据模式
                    largeThreshold: 2000
                };
                const objB = {
                    name: this.queryParams.device.name + variableMap.get(element),
                    type: 'line',
                    xAxisIndex: index,
                    yAxisIndex: index,
                    data: dataBForVar,
                    sampling: 'lttb',
                    large: true,
                    largeThreshold: 2000
                };
                series.push(objA, objB);
                legend.push({
                    data: [objA.name, objB.name],
                    textStyle: { color: "#fff" },
                    top: top
                });
            });

            if (variables.length === 1) {
                grid[0].top = "15%";
                grid[0].bottom = "10%";
                grid[0].height = "auto";
                legend[0].top = "10%";
            }

            const option = {
                tooltip: { trigger: 'axis' },
                legend,
                grid,
                xAxis,
                yAxis,
                series,
                dataZoom: [
                    { type: 'inside', start: 0, end: 100, xAxisIndex: gridIndex },
                    { type: 'slider', start: 0, end: 100, xAxisIndex: gridIndex }
                ]
            };
            this.myChart.setOption(option);


        },
        open() {
            this.title = "跨设备数据对比——" + this.device.name;
        },
        cancel() {
            this.$emit("visibleChange", false);
            if (this.myChart) {
                this.myChart.clear();
            }
            this.queryParams = {};
        }
    }

}
</script>

<style>
.dialog .el-dialog__body {
    padding: 20px 20px 10px;
}
</style>